package com.lgCore.netty.server.handler;

import com.alibaba.fastjson.JSON;
import com.lgCore.cocurrent.AsgCallable;
import com.lgCore.cocurrent.ExecutorScheduler;
import com.lgCore.message.CommonRpcRequest;
import com.lgCore.netty.message.*;
import com.lgCore.netty.server.NettyChannelMap;
import com.lgCore.server.factory.CommonRpcServiceFactory;
import com.lgCore.server.workHandler.invokBean.InvokRpcMethod;
import com.lgCore.util.ExceptionUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;

public class NettyServerHandler extends SimpleChannelInboundHandler<BaseMsg> {
    private ThreadPoolExecutor threadPoolExecutor;
    private static final Logger LOGGER = LoggerFactory.getLogger(NettyServerHandler.class);


    public NettyServerHandler(int threadCount) {
        threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadCount);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //channel失效，从Map中移除
        SocketChannel socketChannel = (SocketChannel) ctx.channel();
        ChannelId channelId = socketChannel.id();
        String idStr = channelId.asLongText();
        LOGGER.info("服务端与客户端断开连接:" + idStr);
        NettyChannelMap.remove((SocketChannel) ctx.channel());
    }


//    @Override
//    protected void messageReceived(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {
//        /**************检验连接是否准确 start*************/
//        if (MsgType.LOGIN.equals(baseMsg.getType())) {
//            LoginMsg loginMsg = (LoginMsg) baseMsg;
//
//            //默认登录成功，不用用户名密码
//            //加入到channel组
//            String loginToken = NettyChannelMap.add((SocketChannel) channelHandlerContext.channel());
//            System.out.println("client" + loginToken + " 登录成功");
//            LoginReplyMsg loginReplyMsg = new LoginReplyMsg();
//            loginReplyMsg.setSuccese(true);
//            loginReplyMsg.setLoginToken(loginToken);
//            channelHandlerContext.channel().writeAndFlush(loginReplyMsg);
//            return;
//        } else {
//            String clientId = baseMsg.getClientId();
//            if (clientId == null) {
//                //说明未登录，或者连接断了，服务器向客户端发起登录请求，让客户端重新登录
//                LoginMsg loginMsg = new LoginMsg();
//                loginMsg.setIsReLog(1);
//                channelHandlerContext.channel().writeAndFlush(loginMsg);
//                return;
//            }
//            Channel channel = NettyChannelMap.get(clientId);
//            if (channel == null) {
//                //说明未登录，或者连接断了，服务器向客户端发起登录请求，让客户端重新登录
//                LoginMsg loginMsg = new LoginMsg();
//                loginMsg.setIsReLog(1);
//                channelHandlerContext.channel().writeAndFlush(loginMsg);
//                return;
//            }
//
//            Channel currentChannel = channelHandlerContext.channel();
//            if (currentChannel != channel) {
//                //登陆id不匹配
//                LoginMsg loginMsg = new LoginMsg();
//                loginMsg.setIsReLog(1);
//                channelHandlerContext.channel().writeAndFlush(loginMsg);
//                return;
//            }
//        }
//        /**************检验连接是否准确 end*************/
//        //具体业务
//        switch (baseMsg.getType()) {
//            case PING: {
//                PingMsg pingMsg = (PingMsg) baseMsg;
//                PingMsg replyPing = new PingMsg();
////                System.out.println("receive client ping:keepalive clientId="+baseMsg.getClientId()+" "+new Date());
//                NettyChannelMap.get(pingMsg.getClientId()).writeAndFlush(replyPing);
//            }
//            break;
//            case ASK: {
//                //收到客户端的请求
//                AskMsg askMsg = (AskMsg) baseMsg;
////                System.out.println("收到RPC客户端端信息：" + JSON.toJSONString(askMsg));
//                try {
//                    //组装invok调用参数
//                    CommonRpcRequest commonRpcRequest = askMsg.getParams().getCommonRpcRequest();
//                    InvokRpcMethod invokRpcMethod = new InvokRpcMethod();
//                    invokRpcMethod.setMethod(commonRpcRequest.getMethodName());
//                    invokRpcMethod.setServicePath(commonRpcRequest.getServiceName());
//                    invokRpcMethod.setParamDatas(commonRpcRequest.getRequestObjects());
//                    invokRpcMethod = CommonRpcServiceFactory.getCommonRpcRouteService().getInvokRpcMethod(invokRpcMethod);
//                    //调用
//                    Object obj =null;
//                    Date date = new Date();
////                    for(int i=0;i<1;i++){
//                        obj = CommonRpcServiceFactory.getCommonRpcRouteService().methodInvoke(invokRpcMethod);
////                    }
//                    System.out.println("接口响应时间："+(new Date().getTime()-date.getTime()));
//                    //结果发送给客户端
//                    ReplyServerBody replyBody = new ReplyServerBody(obj, 1);
//                    ReplyMsg replyMsg = new ReplyMsg();
//                    replyMsg.setBody(replyBody);
//                    replyMsg.setBusinessId(askMsg.getBusinessId());
//                    NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);
//                } catch (Exception e) {
//                    e.printStackTrace();
//                    ReplyServerBody replyBody = new ReplyServerBody(null, 0);
//                    ReplyMsg replyMsg = new ReplyMsg();
//                    replyMsg.setBody(replyBody);
//                    NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);
//                }
//            }
//            break;
//            case REPLY: {
//                //收到客户端回复
//                ReplyMsg replyMsg = (ReplyMsg) baseMsg;
//                ReplyClientBody clientBody = (ReplyClientBody) replyMsg.getBody();
//            }
//            break;
//            case LOGOUT: {
//                //登出
//                NettyChannelMap.remove((SocketChannel) channelHandlerContext.channel());
//            }
//            break;
//
//            default:
//                break;
//        }
//        ReferenceCountUtil.release(baseMsg);
//    }

    /**
     * 捕捉异常，让netty正常运行
     *
     * @param ctx
     * @param e
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e)
            throws Exception {
        String errorMsg = ExceptionUtil.ExceptionDetailAll((Exception) e.getCause());
        LOGGER.info("netty server exception is " + errorMsg);
        if (!(e.getCause() instanceof IOException)) {
            // only log

            LOGGER.error("catch some exception not IOException", e);
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, BaseMsg baseMsg) throws Exception {

//        System.out.println("server msg is "+JSON.toJSONString(baseMsg)+" 时间 "+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        /**************检验连接是否准确 start*************/
        if (MsgType.LOGIN.equals(baseMsg.getType())) {
            LoginMsg loginMsg = (LoginMsg) baseMsg;

            //默认登录成功，不用用户名密码
            //加入到channel组
            String loginToken = NettyChannelMap.add((SocketChannel) channelHandlerContext.channel());
            LOGGER.info("client" + loginToken + " 登录成功");
            LoginReplyMsg loginReplyMsg = new LoginReplyMsg();
            loginReplyMsg.setSuccese(true);
            loginReplyMsg.setLoginToken(loginToken);
            channelHandlerContext.channel().writeAndFlush(loginReplyMsg);
            return;
        } else {
            String clientId = baseMsg.getClientId();
            if (clientId == null) {
                //说明未登录，或者连接断了，服务器向客户端发起登录请求，让客户端重新登录
                LoginMsg loginMsg = new LoginMsg();
                loginMsg.setIsReLog(1);
                channelHandlerContext.channel().writeAndFlush(loginMsg);
                return;
            }
            Channel channel = NettyChannelMap.get(clientId);
            if (channel == null) {
                //说明未登录，或者连接断了，服务器向客户端发起登录请求，让客户端重新登录
                LoginMsg loginMsg = new LoginMsg();
                loginMsg.setIsReLog(1);
                channelHandlerContext.channel().writeAndFlush(loginMsg);
                return;
            }

            Channel currentChannel = channelHandlerContext.channel();
            if (currentChannel != channel) {
                //登陆id不匹配
                LoginMsg loginMsg = new LoginMsg();
                loginMsg.setIsReLog(1);
                channelHandlerContext.channel().writeAndFlush(loginMsg);
                return;
            }
        }
        /**************检验连接是否准确 end*************/
        //具体业务
        switch (baseMsg.getType()) {
            case PING: {
                PingMsg pingMsg = (PingMsg) baseMsg;
                PingMsg replyPing = new PingMsg();
//                LOGGER.info("receive client ping:keepalive clientId="+baseMsg.getClientId()+" "+new Date());
                NettyChannelMap.get(pingMsg.getClientId()).writeAndFlush(replyPing);
            }
            break;
            case ASK: {
                //异步处理转发的逻辑
                AsgCallable asgCallable=new AsgCallable((AskMsg) baseMsg);
                ExecutorScheduler.add(asgCallable);
//                ExecutorScheduler.add(() ->
//                {
//                    //收到客户端的请求
//                    AskMsg askMsg = (AskMsg) baseMsg;
////                LOGGER.info("收到RPC客户端端信息：" + JSON.toJSONString(askMsg));
//                    try {
//                        //组装invok调用参数
//                        CommonRpcRequest commonRpcRequest = askMsg.getParams().getCommonRpcRequest();
//                        InvokRpcMethod invokRpcMethod = new InvokRpcMethod();
//                        invokRpcMethod.setMethod(commonRpcRequest.getMethodName());
//                        invokRpcMethod.setServicePath(commonRpcRequest.getServiceName());
//                        invokRpcMethod.setParamDatas(commonRpcRequest.getRequestObjects());
//                        invokRpcMethod = CommonRpcServiceFactory.getCommonRpcRouteService().getInvokRpcMethod(invokRpcMethod);
//                        //调用
//                        Object obj = null;
//                        Date date = new Date();
//                        ReplyServerBody replyBody = null;
//                        try {
//                            obj = CommonRpcServiceFactory.getCommonRpcRouteService().methodInvoke(invokRpcMethod);
////                        LOGGER.info("接口响应时间："+(new Date().getTime()-date.getTime()));
//                            replyBody = new ReplyServerBody(obj, 1);
//                        } catch (Exception e) {
//                            String errorMsg = ExceptionUtil.ExceptionDetailAll(e);
//                            replyBody = new ReplyServerBody(null, 0);
//                            replyBody.setExceptionMsg(errorMsg);
//                            LOGGER.info("接口调用失败：" + errorMsg);
//                            e.printStackTrace();
//                        }
//                        //多线程调用
////                        ExecutorService executorService = Executors.newCachedThreadPool();
////                        FutureTask<ReplyServerBody> futureTask = (FutureTask<ReplyServerBody>) executorService.submit(new ServiceInvokCallable(invokRpcMethod));
////                        ReplyServerBody replyBody = futureTask.get(RpcBaseCommonEntity.maxExecuteTime, TimeUnit.SECONDS);
//                        //结果发送给客户端
//                        ReplyMsg replyMsg = new ReplyMsg();
//                        replyMsg.setBody(replyBody);
//                        replyMsg.setBusinessId(askMsg.getBusinessId());
////                    LOGGER.info("发送给客户端信息："+JSON.toJSONString(replyMsg));
//                        NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);
//
//
//                    } catch (Exception e) {
//                        e.printStackTrace();
//                        ReplyServerBody replyBody = new ReplyServerBody(null, 0);
//                        ReplyMsg replyMsg = new ReplyMsg();
//                        replyMsg.setBody(replyBody);
//                        replyMsg.setBusinessId(askMsg.getBusinessId());
//                        NettyChannelMap.get(askMsg.getClientId()).writeAndFlush(replyMsg);
//                    }
//                });
            }
            break;
            case REPLY: {
                //收到客户端回复
                ReplyMsg replyMsg = (ReplyMsg) baseMsg;
                ReplyClientBody clientBody = (ReplyClientBody) replyMsg.getBody();
            }
            break;
            case LOGIN:
                break;
            case LOGIN_REPLY:
                break;
            case LOGOUT: {
                //登出
                NettyChannelMap.remove((SocketChannel) channelHandlerContext.channel());
            }
            break;

            default:
                break;
        }
        ReferenceCountUtil.release(baseMsg);

    }


    private class ServerHandlerRunnable implements Runnable {

        private Channel channel;

        private AskMsg askMsg;

        /**
         * @param channel
         * @param askMsg  客户端业务数据
         */
        public ServerHandlerRunnable(Channel channel, AskMsg askMsg) {
            super();
            this.channel = channel;
            this.askMsg = askMsg;
        }


        @Override
        public void run() {
            // TODO Auto-generated method stub
            handleRequestWithSingleThread(channel, askMsg);
        }

    }

    /**
     * 业务处理
     *
     * @param askMsg
     */
    private void handleRequestWithSingleThread(Channel channel, AskMsg askMsg) {
        try {
            AskParams askParams = askMsg.getParams();
            CommonRpcRequest commonRpcRequest = askParams.getCommonRpcRequest();

            InvokRpcMethod invokRpcMethod = new InvokRpcMethod();
            Class<?>[] paramTypes = new Class[]{String.class};
            invokRpcMethod.setMethod(commonRpcRequest.getMethodName());

//            invokRpcMethod.setServicePath("com.lgCore.service.UserService");
            invokRpcMethod.setServicePath(commonRpcRequest.getServiceName());
//            invokRpcMethod.setParamTypes(paramTypes);
            invokRpcMethod.setParamTypes(commonRpcRequest.getArgTypes());
            Object[] paramDatas = new Object[]{"111111"};
//            invokRpcMethod.setParamDatas(paramDatas);
            paramDatas = commonRpcRequest.getRequestObjects();
            invokRpcMethod.setParamDatas(paramDatas);
            invokRpcMethod = CommonRpcServiceFactory.getCommonRpcRouteService().getInvokRpcMethod(invokRpcMethod);
            Object obj = CommonRpcServiceFactory.getCommonRpcRouteService().methodInvoke(invokRpcMethod);
            //回复客户端
            ReplyServerBody replyBody = new ReplyServerBody(obj, 1);
            ReplyMsg replyMsg = new ReplyMsg();
            replyMsg.setBody(replyBody);
            replyMsg.setBusinessId(askMsg.getBusinessId());
            channel.writeAndFlush(replyMsg);
        } catch (Exception e) {
            e.printStackTrace();
            ReplyServerBody replyBody = new ReplyServerBody(null, 0);
            ReplyMsg replyMsg = new ReplyMsg();
            replyMsg.setBody(replyBody);
            channel.writeAndFlush(replyMsg);
        }
    }
}
